package com.smsVerification.service.captcha.impl;

import cn.hutool.http.HttpRequest;
import com.alibaba.fastjson.JSONObject;
import com.smsVerification.config.HttpCode;
import com.smsVerification.pojo.CommonResult;
import com.smsVerification.service.captcha.ICaptchaEditService;
import com.smsVerification.service.captcha.ICaptchaInfoService;
import com.smsVerification.utils.DateTimeValueHandler;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.time.Duration;

/**
 * 极光短信发送
 */
@Service
//刷新配置 解决资源文件与javaConfig的同步问题的，当boot环境中properties值改变，SpringCloud触发，Apollo触发，需要对boot的java config进行刷新处理，因为config初始化之后不会再初始化了，用于SpringCloud Config的配置比较多
@RefreshScope
public class CaptchaEditServiceImpl implements ICaptchaEditService {

    /**
     * 保存手机号与极光验证码ID对应关系的KEY的前缀
     */
    final String CAPTCHA_RECORD_KEY_PREFIX = "CAPTCHA:";

    /**
     * 保存手机号与极光验证码ID对应关系的MAP的KEY
     */
    final String CAPTCHA_RECORD_KEY_SUFFIX = ":VALUE";

    /**
     * 保存手机号发送了多少次验证码的MAP的KEY
     */
    final String CAPTCHA_COUNT_MAP_KEY = "CAPTCHA:COUNT:MAP";

    /**
     * 短信数据的JSON KEY
     */
    final String MESSAGE_ID_KEY = "msg_id";

    /**
     * 极光开发APP KEY
     */
    @Value("${jiguang.jpush.app-key}")
    String JPUSH_APP_KEY;

    /**
     * 极光开发MASTER SECRET
     */
    @Value("${jiguang.jpush.master-secret}")
    String JPUSH_MASTER_SECRET;

    /**
     * 极光短信签名ID
     */
    @Value("${jiguang.jpush.message-sign-id}")
    String JPUSH_MESSAGE_SIGN_ID;

    /**
     * 极光验证码短信ID
     */
    @Value("${jiguang.jpush.captcha-template-id}")
    String JPUSH_CAPTCHA_TEMPLATE_ID;

    @Resource
    ICaptchaInfoService captchaInfoService;

    @Resource
    private RedisTemplate<String, Object> redisTemplate;

    /**
     * 发送手机号验证码
     *
     * @param phoneNumber 解密后的手机号
     * @return 是否成功
     */
    @Override
    public CommonResult<Boolean> sendCaptcha(String phoneNumber) {
        //判断今天短信验证发送次数是否合规
        if (!captchaInfoService.isCaptchaRequestAvailable(phoneNumber)) {
            return new CommonResult<>(HttpCode.WRONG_PARAM, "今日发送数量过多", false);
        }

        //发送短信验证码
        String msgId = sendCaptchaNetworkHandler(phoneNumber);
        if (msgId != null) {
            //设置Redis中对于手机号和msgId的记录
            setRedisRecord(phoneNumber, msgId);
            return new CommonResult<>(HttpCode.SUCCESS, "发送成功", true);
        } else {
            return new CommonResult<>(HttpCode.INTERNAL_ERROR, "发送失败", false);
        }

    }

    /**
     * 发送手机号验证码
     * 参考文档：https://docs.jiguang.cn/jsms/server/rest_api_jsms#功能说明
     */
    private String sendCaptchaNetworkHandler(String phoneNumber) {
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("mobile", phoneNumber);
        jsonObject.put("sign_id", JPUSH_MESSAGE_SIGN_ID);
        jsonObject.put("temp_id", JPUSH_CAPTCHA_TEMPLATE_ID);

        //返回msg_id
        String result = HttpRequest.post("https://api.sms.jpush.cn/v1/codes")
                .basicAuth(JPUSH_APP_KEY, JPUSH_MASTER_SECRET)
                .body(jsonObject.toString())
                .timeout(20000)
                .execute().body();

        JSONObject resultJson = JSONObject.parseObject(result);
        if (resultJson.containsKey(MESSAGE_ID_KEY)) {
            return resultJson.getString(MESSAGE_ID_KEY);
        } else {
            return null;
        }

    }

    /**
     * 设置Redis中对于手机号和msgId的记录（方便后续调用验证码验证api）
     *
     * @param phoneNumber 手机号
     * @param msgId       消息的Id
     */
    private void setRedisRecord(String phoneNumber, String msgId) {
        //获取Key
        String recordKey = getRecordKey(phoneNumber);
        //增加手机号和验证码ID对应关系的记录
        redisTemplate.opsForValue().set(recordKey, msgId);
        //设置过期时间
        //由于极光验证码自带验证码过期功能，所以只需要设置一个比极光自带验证码过期时间（300秒）长的就可以
        //设置600s
        redisTemplate.expire(recordKey, Duration.ofSeconds(600));

        //增加验证码发送数量的记录
        redisTemplate.opsForHash().increment(CAPTCHA_COUNT_MAP_KEY, phoneNumber, 1);
        //设置验证码发送数量MAP的过期时间
        redisTemplate.expireAt(CAPTCHA_COUNT_MAP_KEY, DateTimeValueHandler.getRedisMidnightExpiredTime());
    }

    /**
     * 获取对应手机号在Redis中的key
     * 举例：CAPTCHA:13577401518:VALUE
     *
     * @return 手机号在Redis中的key
     */
    String getRecordKey(String phone) {
        return CAPTCHA_RECORD_KEY_PREFIX + phone + CAPTCHA_RECORD_KEY_SUFFIX;
    }
}
